var RowNode = agGrid.RowNode;

module.exports = function(api){
    return {
        execute: function(rowsToGroup){
            var result;

            var groupedCols = api.columnController.getRowGroupColumns();

            if (groupedCols.length > 0) {
                var expandByDefault;
                if (api.gridOptionsWrapper.isGroupSuppressRow()) {
                    expandByDefault = -1;
                } else {
                    expandByDefault = api.gridOptionsWrapper.getGroupDefaultExpanded();
                }
                result = group(rowsToGroup, groupedCols, expandByDefault,api);
            } else {
                result = rowsToGroup;
            }

            return result;
        }
    }
}

function isExpanded(expandByDefault, level) {
    if (typeof expandByDefault === 'number') {
        if (expandByDefault===-1) {
            return true;
        } else {
            return level < expandByDefault;
        }
    } else {
        return false;
    }
}
function group(rowNodes, groupedCols, expandByDefault,api) {

    var topMostGroup = new RowNode(api.eventService, api.gridOptionsWrapper, api.selectionController);
    topMostGroup.level = -1;
    topMostGroup.children = [];
    topMostGroup._childrenMap = {};

    var allGroups = [];
    allGroups.push(topMostGroup);

    var levelToInsertChild = groupedCols.length - 1;
    var i;
    var currentLevel;
    var node;
    var currentGroup;
    var groupKey;
    var nextGroup;
    var includeParents = !api.gridOptionsWrapper.isSuppressParentsInRowNodes();

    // start at -1 and go backwards, as all the positive indexes
    // are already used by the nodes.
    var index = -1;

    for (i = 0; i < rowNodes.length; i++) {
        node = rowNodes[i];

        // all leaf nodes have the same level in this grouping, which is one level after the last group
        node.level = levelToInsertChild + 1;

        for (currentLevel = 0; currentLevel < groupedCols.length; currentLevel++) {
            var groupColumn = groupedCols[currentLevel];
            groupKey = api.valueService.getValue(groupColumn, node);

            if (currentLevel === 0) {
                currentGroup = topMostGroup;
            }

            // if group doesn't exist yet, create it
            nextGroup = currentGroup._childrenMap[groupKey];
            if (!nextGroup) {
                nextGroup = new RowNode(api.eventService, api.gridOptionsWrapper, api.selectionController);
                nextGroup.group = true;
                nextGroup.field = groupColumn.getColDef().field;
                nextGroup.id = index--;
                nextGroup.key = groupKey;
                nextGroup.expanded = isExpanded(expandByDefault, currentLevel);
                nextGroup.children = [];
                // for top most level, parent is null
                nextGroup.parent = null;
                nextGroup.allChildrenCount = 0;
                nextGroup.level = currentGroup.level + 1;
                // this is a temporary map, we remove at the end of this method
                nextGroup._childrenMap = {};

                if (includeParents) {
                    nextGroup.parent = currentGroup === topMostGroup ? null : currentGroup;
                }
                currentGroup._childrenMap[groupKey] = nextGroup;
                currentGroup.children.push(nextGroup);
                allGroups.push(nextGroup);
            }

            nextGroup.allChildrenCount++;

            if (currentLevel == levelToInsertChild) {
                if (includeParents) {
                    node.parent = nextGroup === topMostGroup ? null : nextGroup;
                }
                nextGroup.children.push(node);
            } else {
                currentGroup = nextGroup;
            }
        }

    }

    //remove the temporary map
    for (i = 0; i < allGroups.length; i++) {
        delete allGroups[i]._childrenMap;
    }

    return topMostGroup.children;


};
